package org.holoeverywhere.preference; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.content.res.TypedArray; import android.net.Uri; import android.os.Bundle; import android.util.AttributeSet; import android.util.TypedValue; import org.holoeverywhere.app.GenericInflater; import org.holoeverywhere.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; public class PreferenceInflater extends GenericInflater<Preference, PreferenceGroup> { private static final String EXTRA_TAG_NAME = "extra"; private static final String INTENT_TAG_NAME = "intent"; private static void parseBundleExtra(Resources resources, String tagName, AttributeSet attrs, Bundle outBundle) throws XmlPullParserException { TypedArray sa = resources.obtainAttributes(attrs, R.styleable.Extra); String name = sa.getString(R.styleable.Extra_android_name); if (name == null) { sa.recycle(); throw new XmlPullParserException("<" + tagName + "> requires an holo:name attribute at " + attrs.getPositionDescription()); } TypedValue v = sa.peekValue(R.styleable.Extra_android_value); if (v != null) { if (v.type == TypedValue.TYPE_STRING) { CharSequence cs = v.coerceToString(); outBundle.putCharSequence(name, cs); } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { outBundle.putBoolean(name, v.data != 0); } else if (v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT) { outBundle.putInt(name, v.data); } else if (v.type == TypedValue.TYPE_FLOAT) { outBundle.putFloat(name, v.getFloat()); } else { sa.recycle(); throw new XmlPullParserException("<" + tagName + "> only supports string, integer, float, color, and boolean at " + attrs.getPositionDescription()); } } else { sa.recycle(); throw new XmlPullParserException("<" + tagName + "> requires an holo:value attribute at " + attrs.getPositionDescription()); } sa.recycle(); } private static Intent parseIntent(Resources resources, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { Intent intent = new Intent(); TypedArray sa = resources.obtainAttributes(attrs, R.styleable.Intent); intent.setAction(sa.getString(R.styleable.Intent_android_action)); String data = sa.getString(R.styleable.Intent_android_data); String mimeType = sa.getString(R.styleable.Intent_android_mimeType); intent.setDataAndType(data != null ? Uri.parse(data) : null, mimeType); String packageName = sa.getString(R.styleable.Intent_android_targetPackage); String className = sa.getString(R.styleable.Intent_android_targetClass); if (packageName != null && className != null) { intent.setComponent(new ComponentName(packageName, className)); } sa.recycle(); int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String nodeName = parser.getName(); if (nodeName.equals("category")) { sa = resources.obtainAttributes(attrs, R.styleable.IntentCategory); String cat = sa.getString(R.styleable.IntentCategory_android_name); sa.recycle(); if (cat != null) { intent.addCategory(cat); } XmlUtils.skipCurrentTag(parser); } else if (nodeName.equals("extra")) { Bundle bundle = new Bundle(); parseBundleExtra(resources, "extra", attrs, bundle); intent.putExtras(bundle); XmlUtils.skipCurrentTag(parser); } else { XmlUtils.skipCurrentTag(parser); } } return intent; } private PreferenceManager mPreferenceManager; public PreferenceInflater(Context context, PreferenceManager preferenceManager) { super(PreferenceInit.context(context)); init(preferenceManager); } public PreferenceInflater(PreferenceInflater original, PreferenceManager preferenceManager, Context newContext) { super(original, PreferenceInit.context(newContext)); init(preferenceManager); } @Override public PreferenceInflater cloneInContext(Context newContext) { return new PreferenceInflater(this, mPreferenceManager, newContext); } private void init(PreferenceManager preferenceManager) { mPreferenceManager = preferenceManager; registerPackage(PreferenceInit.PACKAGE); } @Override protected boolean onCreateCustomFromTag(XmlPullParser parser, Preference parentPreference, AttributeSet attrs) throws XmlPullParserException { final String tag = parser.getName(); if (tag.equals(PreferenceInflater.INTENT_TAG_NAME)) { Intent intent = null; try { intent = parseIntent(getContext().getResources(), parser, attrs); } catch (IOException e) { XmlPullParserException ex = new XmlPullParserException( "Error parsing preference"); ex.initCause(e); throw ex; } if (intent != null) { parentPreference.setIntent(intent); } return true; } else if (tag.equals(PreferenceInflater.EXTRA_TAG_NAME)) { parseBundleExtra(getContext().getResources(), PreferenceInflater.EXTRA_TAG_NAME, attrs, parentPreference.getExtras()); try { XmlUtils.skipCurrentTag(parser); } catch (IOException e) { XmlPullParserException ex = new XmlPullParserException( "Error parsing preference"); ex.initCause(e); throw ex; } return true; } return false; } @Override protected PreferenceGroup onMergeRoots(PreferenceGroup givenRoot, boolean attachToGivenRoot, PreferenceGroup xmlRoot) { if (givenRoot == null) { xmlRoot.onAttachedToHierarchy(mPreferenceManager); return xmlRoot; } else { return givenRoot; } } }